package com.blue.gateway.client.anno;

import cn.hutool.http.HttpStatus;
import com.blue.common.enums.ServiceEnum;
import com.blue.common.exception.BaseException;
import com.blue.gateway.bean.constants.GatewayHeaderKey;
import com.blue.gateway.client.strategy.AbstractStrategyGetLoginUser;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

import java.lang.annotation.Annotation;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Base64;
import java.util.List;
import java.util.Optional;

/**
 * 解析注解@LoginUserInfo方法，获取当前登录用户信息[网关层会对token做基础的校验，客户端，也就是调用此处包的服务只需要解析即可]
 *
 * @author liulei
 * @version 1.0
 */
@Slf4j
public class LoginUserResolver implements HandlerMethodArgumentResolver {

    private static final Base64.Decoder DECODER = Base64.getDecoder();

    private List<AbstractStrategyGetLoginUser> strategyGetLoginUser;

    public LoginUserResolver(List<AbstractStrategyGetLoginUser> strategyGetLoginUser) {
        this.strategyGetLoginUser = strategyGetLoginUser;
    }

    /**
     * 该方法相同接口只会执行一次
     */
    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        Annotation[] annotations = parameter.getParameterAnnotations();
        Optional<Annotation> optional = Arrays.stream(annotations).filter(annotation -> annotation instanceof LoginUser).findAny();
        if (optional.isPresent()) {
            LoginUser annotation = (LoginUser) optional.get();
            if (annotation.valid()) {
                return true;
            }
        }
        return false;
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest,
                                  WebDataBinderFactory binderFactory) throws Exception {
        String requestNo = webRequest.getHeader(GatewayHeaderKey.REQUEST_NO);
        String requestScope = webRequest.getHeader(GatewayHeaderKey.SCOPE);
        String token = webRequest.getHeader(GatewayHeaderKey.TOKEN);
        // 用户信息的header，需要利用feign做透传处理,即A->B->C的时候，header信息可以一直保持被每个服务获取到
        String codedUserInfo = webRequest.getHeader(GatewayHeaderKey.USER_INFO);
        byte[] decode = DECODER.decode(codedUserInfo);
        String userInfo = new String(decode, StandardCharsets.UTF_8);
        ServiceEnum scope = ServiceEnum.getByCode(Integer.valueOf(requestScope));
        log.debug("请求no: {}", requestNo);
        log.debug("请求scope: {}", scope.getDesc());
        log.debug("请求token: {}", token);
        log.debug("登录user_info: {}", userInfo);
        Optional<AbstractStrategyGetLoginUser> any = strategyGetLoginUser.stream().filter(strategy -> strategy.support(scope)).findAny();
        if (!any.isPresent()) {
            log.info("请求服务不存在");
            throw new BaseException(HttpStatus.HTTP_BAD_REQUEST, "请求服务不存在");
        }
        return any.get().parseJsonStr2UserInfo(userInfo);
    }

}
